/*******************************************************************************
 * Copyright (c) 2009 Ravenhearte Design.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 	*	Redistributions of source code must retain the above copyright
 * 		notice, this list of conditions and the following disclaimer.
 * 
 * 	*	Redistributions in binary form must reproduce the above copyright
 * 		notice, this list of conditions and the following disclaimer in the
 * 		documentation and/or other materials provided with the distribution.
 * 
 * 	*	Neither the name of 'Ravenhearte Design' nor the names of its contributors 
 * 		may be used to endorse or promote products derived from this software 
 * 		without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

package org.ravenhearte.engine.helpers;

import java.util.HashSet;
import java.util.Iterator;

import org.ravenhearte.engine.input.EventHandler;
import org.ravenhearte.engine.input.InputEvent;
import org.ravenhearte.engine.input.InputEventManager;
import org.ravenhearte.engine.input.InputEvent.EventType;
import org.ravenhearte.engine.input.InputEventManager.Queue;

import com.jme.intersection.BoundingPickResults;
import com.jme.intersection.PickResults;
import com.jme.math.Ray;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Geometry;
import com.jme.scene.Node;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.RenderState.StateType;
import com.jme.system.DisplaySystem;

public class GeometryXRayer implements EventHandler {
	private Node node;
	private HashSet<Geometry> transparentGeometry;
	private BlendState bs;

	public GeometryXRayer(Node node) {
		this.node = node;

		transparentGeometry = new HashSet<Geometry>();

		ColorRGBA color = new ColorRGBA(0, 0, 0, .3f);
		bs = DisplaySystem.getDisplaySystem().getRenderer().createBlendState();
		bs.setBlendEnabled(true);
		bs.setSourceFunction(BlendState.SourceFunction.ConstantAlpha);
		bs.setDestinationFunction(BlendState.DestinationFunction.OneMinusConstantAlpha);
		bs.setConstantColor(color);
		bs.setEnabled(true);

		loadEvents();
		
		InputEvent evnt = new InputEvent();
		evnt.parent = this;
		evnt.type = EventType.CUSTOM;
		evnt.textId = "CameraChange";
		InputEventManager.eM.generateEvent(evnt);
	}

	private void loadEvents() {
		InputEvent evnt = new InputEvent();
		evnt.parent = this;
		evnt.type = EventType.CUSTOM;
		evnt.textId = "CameraChange";
		InputEventManager.eM.registerEvent(Queue.WORLD, evnt);
	}

	@Override
	public void unloadEvents() {
		InputEventManager.eM.unregisterEvents(this);
		if (!transparentGeometry.isEmpty()) {
			Iterator<Geometry> it = transparentGeometry.iterator();
			while (it.hasNext()) {
				Geometry geo = it.next();
				geo.clearRenderState(StateType.Blend);
				geo.updateRenderState();
				it.remove();
			}
		}
	}

	@Override
	public boolean onEvent(InputEvent ev) {
		switch (ev.type) {
		case CUSTOM:
			if (ev.textId.contentEquals("CameraChange")) {
				DisplaySystem display = DisplaySystem.getDisplaySystem();
				Camera cam = display.getRenderer().getCamera();

				int x = display.getWidth() / 2;
				int y = display.getHeight() / 2;

				Vector2f screenPos = new Vector2f(x, y);

				Vector3f startPoint = cam.getWorldCoordinates(screenPos, 0);
				Vector3f direction = cam.getDirection();

				Ray ray = new Ray(startPoint, direction);

				PickResults results = new BoundingPickResults();
				results.clear();
				results.setCheckDistance(true);
				node.findPick(ray, results);

				HashSet<Geometry> foundWalls = new HashSet<Geometry>();

				if (results.getNumber() != 0) {
					for (int i = 0; i < results.getNumber(); i++) {
						Geometry picked = results.getPickData(i)
								.getTargetMesh();
						if (picked.getName().contains("Wall")) {
							foundWalls.add(picked);
						}
					}
				}

				if (!transparentGeometry.isEmpty()) {
					transparentGeometry.removeAll(foundWalls);
					Iterator<Geometry> it = transparentGeometry.iterator();
					while (it.hasNext()) {
						Geometry geo = it.next();
						geo.clearRenderState(StateType.Blend);
						geo.updateRenderState();
						it.remove();
					}
				}

				transparentGeometry.addAll(foundWalls);
				Iterator<Geometry> it = transparentGeometry.iterator();
				while (it.hasNext()) {
					Geometry geo = it.next();
					geo.setRenderState(bs);
					geo.updateRenderState();
				}
				return false;
			}
		}
		return false;
	}

}
